package dynamic

import (
	"bufio"
	"encoding/json"
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"sort"
)

// TraceRuntimeDeps executes execCmd under strace to record file accesses.
// It writes the raw trace to runtime_deps.log and the unique file paths
// to runtime_deps.json. The slice of unique paths is also returned.
func TraceRuntimeDeps(execCmd []string) ([]string, error) {
	if len(execCmd) == 0 {
		return nil, errors.New("execCmd is empty")
	}

	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	logPath := filepath.Join(wd, "runtime_deps.log")
	jsonPath := filepath.Join(wd, "runtime_deps.json")

	args := append([]string{"-f", "-e", "trace=file", "-o", logPath}, execCmd...)
	cmd := exec.Command("strace", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return nil, err
	}

	f, err := os.Open(logPath)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	re := regexp.MustCompile(`"(/[^"]+)"`)
	seen := make(map[string]struct{})
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		matches := re.FindAllStringSubmatch(line, -1)
		for _, m := range matches {
			if len(m) > 1 {
				seen[m[1]] = struct{}{}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	var paths []string
	for p := range seen {
		paths = append(paths, p)
	}
	sort.Strings(paths)

	data, err := json.MarshalIndent(paths, "", "  ")
	if err != nil {
		return nil, err
	}
	if err := os.WriteFile(jsonPath, data, 0644); err != nil {
		return nil, err
	}

	return paths, nil
}
